﻿// pdf_tool.cpp: 定义应用程序的入口点。
//

#include <iostream>
#include <vector>
#include <filesystem>
#include <regex>
#include <string>
#include <format>

#include <podofo/podofo.h>

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>

using namespace std;
using namespace PoDoFo;

template<typename C, typename F>
void operate_front(C& container, F func)
{
	while (!container.empty())
	{
		auto iter = container.front();
		container.pop_front();

		func(iter);
	}
}

void GetPathFileAll(string_view path, vector<string>& ret, string_view regex /*= ""*/)
{
	using directory_iterator = filesystem::directory_iterator;
	list<directory_iterator> vec_path;

	directory_iterator path_iter{ path };
	vec_path.push_back(path_iter);

	bool no_reg = true;
	std::regex reg;
	if (!regex.empty())
	{
		reg = string{ regex };
		no_reg = false;
	}


	operate_front(vec_path, [&](const directory_iterator& iter_path)
		{
			for (auto& fe : iter_path)
			{
				if (fe.status().type() == std::filesystem::file_type::directory)
				{//不递归
					//vec_path.emplace_back(filesystem::directory_iterator{ fe });
				}
				else
				{
					string path_name = fe.path().string();

					if (no_reg || std::regex_search(path_name, reg))
						ret.emplace_back(path_name);
				}
			}
		});
}


int main()
{
	//注意：这里并没有编译podofo库，只是引用动态链接库

	cout << format("{:=^32}", "pdf合并工具v1.1") << endl;
	cout << "①、快速将多个文件合并为1个pdf" << endl;
	cout << "②、支持格式：pdf、常见图像" << endl;
	cout << "③、将文件放入exe的目录" << endl;
	cout << "④、修改名字进行排序，比如1、2、3" << endl;
	cout << "by略游，源码位置：" << endl;
	cout << "https://gitee.com/lveyou/pdf_tool" << endl;
	cout << format("{:=^32}", "") << endl;

	filesystem::path p = filesystem::current_path();
	vector<string> all_file;
	GetPathFileAll(p.string(), all_file, ".(pdf|png|jpg|jpeg|gif|bmp)$");
	//未找到文件
	if (all_file.empty())
	{
		cout << "未找到pdf文件，请将文件复制到exe目录！" << endl;
		cin.get();
		return 0;
	}

	//排序一下
	sort(all_file.begin(), all_file.end());
	//
	cout << "检测到以下文件：" << endl;
	for (auto& iter : all_file)
	{
		filesystem::path p{ iter };
		string ext = p.extension().string();
		string name = p.filename().string();
		cout << format("文件名：{}", name) << endl;

	}
	cout << "按回车键开始合并！（文件会合并到bin/out.pdf）" << endl;
	cin.get();

	std::filesystem::path p0{ "bin/" };
	std::filesystem::path p1{ "tmp/" };
	create_directories(p0);
	create_directories(p1);

	PdfMemDocument pdf_out;
	vector<PdfMemDocument> all_pdf;
	for (string& iter : all_file)
	{
		filesystem::path p{ iter };
		string ext = p.extension().string();
		string name = p.filename().string();
		string stem = p.stem().string();
		if (ext == ".pdf")
		{
			PdfMemDocument pdf(iter.c_str());
			pdf_out.Append(pdf);
		}
		else
		{//图像
			//统一转为png格式
			int texWidth, texHeight, texChannels;
			stbi_uc* pixels = stbi_load(iter.c_str(),
				&texWidth, &texHeight, &texChannels, STBI_rgb_alpha);

			if (!pixels)
			{
				cout << format("加载图像失败：{}", iter);
				continue;
			}
			iter = format("tmp/{}.png", stem);
			stbi_write_png(iter.c_str(), texWidth, texHeight, 4, pixels, 0);
			stbi_image_free(pixels);

			//直接操作输出
			//PdfMemDocument pdf;
			PoDoFo::PdfPainter painter;
			PoDoFo::PdfPage* pPage;
			PoDoFo::PdfImage image(&pdf_out);
			image.LoadFromFile(iter.c_str());

			PoDoFo::PdfRect size;
			if (true)
			{
				size = PoDoFo::PdfPage::CreateStandardPageSize(PoDoFo::ePdfPageSize_A4, false);
			}
			else
			{
				size = PoDoFo::PdfRect(0.0, 0.0, image.GetWidth(), image.GetHeight());
			}

			pPage = pdf_out.CreatePage(size);
			double dScaleX = size.GetWidth() / image.GetWidth();
			double dScaleY = size.GetHeight() / image.GetHeight();
			double dScale = PoDoFo::PDF_MIN(dScaleX, dScaleY);

			painter.SetPage(pPage);

			double top_side = -50;
			if (dScale < 1.0)
			{
				double s = dScale * 0.85;
				double dX = (size.GetWidth() - image.GetWidth() * s) / 2.0;
				double dY = size.GetHeight() - image.GetHeight() * s;
				painter.DrawImage(dX, dY + top_side, &image, s, s);
			}
			else
			{
				// Center Image
				double dX = (size.GetWidth() - image.GetWidth()) / 2.0;
				double dY = (size.GetHeight() - image.GetHeight()) / 1.0 - 50;
				painter.DrawImage(dX, dY + top_side, &image);
			}

			painter.FinishPage();
			//pdf_out.Append(pdf);
		}
	}

#ifdef TEST_FULL_SCREEN
	pdf_out.SetUseFullScreen();
#else
	pdf_out.SetPageMode(ePdfPageModeUseBookmarks);
	pdf_out.SetHideToolbar();
	pdf_out.SetPageLayout(ePdfPageLayoutTwoColumnLeft);
#endif

	pdf_out.Write("bin/out.pdf");
	
	return 0;
}
